<?php

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 * Description of BTreeDataObjWithGroup
 *
 * @author I062261
 */
class BTreeEntity extends BEntity {

    const node_root = 'root';
    const delimiter = '\\\/.|>';
    const Pattern_Delimiter = "/[.\\/|]/";

    public $name = null;
    public $parentId = null;
    public $fullName = null;
    public $spaceId;
    public $appId;

    public function __construct($item = NULL, $context = NULL) {

        /*

          $repository = $this->getRepository();

          $count = $repository->getCount();

          //add root node and return it
          if ($count <= 0) {
          $row = $this->getRepository()->getNewRow();
          $row->attributes['name'] = 'root';
          $row->attributes['fullname'] = 'root';
          $row->attributes['description'] = 'root_node';
          $row->save();
          //$this->getRepository()->loadEntity($row);
          if (method_exists($this, 'initTreeEntityBeforeFirstLoad'))
          $this->initTreeEntityBeforeFirstLoad();
          if (method_exists($this, 'initTreeEntityBeforeLoad'))
          $this->initTreeEntityBeforeLoad();

          //return;
          }
         * 
         */


        parent::__construct($item, $context);
    }

    //put your code here
    public function load($item = NULL) {
        //parent::load($data);
        //by defalut, load root node    
        // $repository = BRepositoryFactory::createRepository2();        

        parent::load($item);
    }

    //this function will add array of  child into tree
    public function addRecursiveChildren($children, $parent = NULL, $childContext = NULL) {

        if ($children == NULL || !is_array($children))
            return FALSE;

        $theParent = $parent == NULL ? $this : $parent;

        if ($theParent instanceof BTreeEntity) {
            foreach ($children as $key => $child) {
                if ($childContext == NULL)
                    if (isset($key) && is_string($key)) {
                        $theParent->addChildItem($key, $childContext);
                        $theParent = $theParent->getChild($key);
                    }
                if (isset($child) && is_string($child)) {
                    $theParent->addChildItem($child, $childContext);
                }
                if (is_array($child) && $child != null) {
                    $theParent->addRecursiveChildren($child, $theParent, $childContext);
                }
            }
        }
    }

    public function addChildItem($item, $data = null) {
        $context = $item;
        if (is_string($context)) {
            $name = $context;
            $context = array();
            $context['name'] = $name;
        }
        $context = $this->getRepository()->populateFindContext($context);
        $childRow = $this->getRepository()->getRow()->getChild($context);
        if (!$childRow instanceof BRow || $childRow->getId() == NULL) {
            //$attributes = $this->getRepository()->populateAttributeList($item);
            $parentAttributes = $this->getRepository()->populateAttributeList();
            $attributes = $this->getRepository()->populateAttributeList($item);
            //add parent attributes into child by default
            $attributes += $parentAttributes;
            if (isset($attributes['_id']))
                unset($attributes['_id']);
            if (isset($attributes['fullname']))
                unset($attributes['fullname']);
            if (isset($attributes['parent_id']))
                unset($attributes['parent_id']);
            //$childRow->attributes += $attributes;
            $childRow = $this->getRepository()->getRow()->addChild($attributes);
        } else {
            $parentAttributes = $this->getRepository()->populateAttributeList();
            $attributes = $this->getRepository()->populateAttributeList($item);
            //add parent attributes into child by default
            $attributes += $parentAttributes;
            if (isset($attributes['_id']))
                unset($attributes['_id']);
            if (isset($attributes['fullname']))
                unset($attributes['fullname']);
            if (isset($attributes['name']))
                unset($attributes['name']);
            if (isset($attributes['parent_id']))
                unset($attributes['parent_id']);
            $childRow->attributes = $attributes + $childRow->attributes;
//            $childRow->attributes['parent_id'] = $this->getId();
            $childRow->save();
        }
        $class = get_class($this);
        $child = new $class();
        $child->getRepository()->loadEntity($childRow);
        if ($child instanceof BTreeEntity) {
            $fullName = $child->getFullName();
            if ($child->fullName == NULL) {
                $child->fullName = $fullName;
                $child->save();
            }
        }
        return $child;
    }

    public function addChild($item, $data = NULL) {
        return $this->addChildItem($item, $data);
    }

    public function getTreeListData($indent = '--') {
        $result = array();

        //$repository = BRepositoryFactory::createRepository2();
        $repository = $this->getRepository();
        $items = $repository->getChildren($this, NULL);
        foreach ($items as $id => $item) {
            $result[$item->id] = $item->name;
            $this->getSubItemListData($result, $item, $indent);
        }

        return $result;
    }

    function getSubItemListData(&$result, $parent, $indent = '--') {
        //$repository = BRepositoryFactory::createRepository2();
        $repository = $this->getRepository();
        $items = $repository->getChildren($parent, NULL);
        foreach ($items as $id => $item) {
            $result[$item->id] = $indent . $item->name;
            $this->getSubItemListData($result, $item, $indent . '--');
        }
    }

    /**
     * 
     * @param type $recursive
     * @param type $data
     * @return \BRole|boolean
     */
    public function getChildren($context = null, $recursive = FALSE, &$recursiveItems = array()) {

        if (is_string($context)) {
            $name = $context;
            $context = array();
            $context['name'] = $name;
        }

        $children = array();
        $rowContext = NULL;
        if ($context != NULL)
            $rowContext = $this->getRepository()->populateAttributeList($context);
        $rows = $this->getRepository()->getRow()->getChildren($recursive, $rowContext, $recursiveItems);
        foreach ($rows as $row) {
            $class = get_class($this);
            $entity = new $class();
            $entity->load($row);
            $children[$row->getId()] = $entity;
        }
        return $children;
    }

    public function getChildrenAsLeaf($context = null, $recursive = TRUE) {
        $children = $this->getChildren($context, $recursive);
        $rChildren = array();
        foreach ($children as $id => $child) {
            if (!$child->haveChildren()) {
                $rChildren[$id] = $child;
            }
        }
        return $rChildren;
    }

    public function getParent($recursive = FALSE, $context = null, &$recursiveItems = array()) {
        $class = get_class($this);
        if ($this->parentId != NULL && !$recursive) {
            $parentId = $this->parentId;
            if (is_numeric($parentId) && $parentId > 0)
                return new $class($parentId);
        }
        if ($context != NULL)
            $rowContext = $this->getRepository()->populateAttributeList($context);
        else {
            $rowContext = $context;
        }
        $returnRows = $this->getRepository()->getRow()->getParent($recursive, $rowContext);

        if ($recursive && is_array($returnRows)) {
            $parentList = array();
            $rows = $returnRows;
            foreach ($rows as $row) {
                $class = get_class($this);
                $parent = new $class();
                $parent->getRepository()->loadEntity($row);
                if ($parent->getId() != 1)
                    $parentList[$parent->getId()] = $parent;
            }
            return $parentList;
        }
        else {
            $row = $returnRows;
            $class = get_class($this);
            $parent = new $class();
            $parent->getRepository()->loadEntity($row);
            return $parent;
        }

        return FALSE;
    }

    /**
     * 
     * @param type $data
     * @return \BTreeEntity
     */
    public static function getRoot($data = null) {

        $class = get_called_class();
        $entity = new $class();

        $count = $entity->getRepository()->getCount();
        if ($count > 0) {
            //$entity = $class::find(array('name'=>'root','parent'=>0));
            //if ($entity instanceof BTreeEntity)
            //return $entity;
            $row = $entity->getRepository()->getRow(array('name' => 'root', 'parentId' => 0));
            if ($row->getId() != NULL) {
                $entity->load($row);
            }

            return $entity;
            //return new $class($row->getId());
        } else {
            $row = $entity->getRepository()->getNewRow();
            $row->attributes['name'] = 'root';
            $row->attributes['fullname'] = 'root';
            $row->attributes['parent_id'] = 0;
            $row->save();
            if (method_exists($entity, 'initTreeEntityBeforeFirstLoad'))
                $entity->initTreeEntityBeforeFirstLoad();
            if (method_exists($entity, 'initTreeEntityBeforeLoad'))
                $entity->initTreeEntityBeforeLoad();
        }
        if ($row != NULL && $row->getId() > 0) {
            $class = get_called_class();
            $entity = new $class();
            $entity->getRepository()->loadEntity($row);
            return $entity;
        }
        return FALSE;
    }

    public function haveChildren($data = null) {
        $children = $this->getChildren();

        if ($children == NULL || $children == FALSE || empty($children))
            return FALSE;

        return TRUE;
    }

    public function haveChild($data = NULL) {
        return $this->haveChildren($data);
    }

    public function isChildOf($item, $recursive = TRUE) {

        $className = get_class($this);

        if ($item instanceof $className) {
            if ($item->getId() == $this->getId())
                return TRUE;
        }

        $parents = $this->getParent($recursive);

        foreach ($parents as $obj) {
            if ($item instanceof $className) {
                if ($obj->getId() == $item->getId())
                    return TRUE;
            }
            if (is_numeric($item)) {
                if ($obj->getId() == $item)
                    return TRUE;
            }
            if (is_string($item)) {
                if ($obj->getName() == $item)
                    return TRUE;
            }
        }

        return FALSE;
    }

    public function isParentOf($item, $recursive = TRUE) {

        $className = get_class($this);

        if ($item instanceof $className) {
            if ($item->getId() != NULL) {
                return $item->isChildOf($this, $recursive);
            }
        }

        $children = $this->getChildren($item, $recursive);

        foreach ($children as $obj) {
            if ($item instanceof $className) {
                if ($obj->getId() == $item->getId())
                    return TRUE;
            }
            if (is_numeric($item)) {
                if ($obj->getId() == $item)
                    return TRUE;
            }
            if (is_string($item)) {
                if ($obj->getName() == $item)
                    return TRUE;
            }
        }

        return FALSE;
    }

    public function getChild($context, $recursive = FALSE) {

        $name = NULL;

        $myFullName = $this->getFullName();

        if (is_string($context)) {
            $name = $context;
            $context = array();
            $context['name'] = $name;
            if (isset($this->appId) && $this->appId != NULL && $this->appId != 0)
                $context['appId'] = $this->appId;
            if (isset($this->spaceId) && $this->spaceId != NULL && $this->spaceId != 0)
                $context['spaceId'] = $this->spaceId;
        }

        if ($context instanceof BTreeEntity) {
            $name = $context->getName();
        }

        if (is_array($context)) {
            $name = $context['name'];
        }

        $rowContext = $this->getRepository()->populateFindContext($context);

        if ($myFullName != NULL && $name != NULL) {
            $names = preg_split(self::Pattern_Delimiter, $name);
            $theName = NULL;
            foreach ($names as $aName) {
                if ($theName == NULL) {
                    $theName = $aName;
                } else {
                    $theName.='.' . $aName;
                }
            }
            if (isset($rowContext['name']))
                $rowContext['name'] = end($names);
            if ($myFullName == 'root')
                $childFullName = $theName;
            else
                $childFullName = $myFullName . '.' . $theName;
            if (is_array($rowContext)) {
                $rowContext['fullname'] = $childFullName;
            }
            //if($this->getId()!=NULL){
            // $rowContext['parent_id'] = $this->getId();
            //}
            $childRow = $this->getRepository()->getRow($rowContext);
        } else {
            $childRow = $this->getRepository()->getRow()->getChild($rowContext);
        }
        if ($childRow instanceof BRow && $childRow->getId() != NULL) {
            $class = get_class($this);
            $id = $childRow->getId();
            $entity = new $class();
            if ($entity instanceof BEntity)
                $entity->getRepository()->loadEntity($childRow);
            return $entity;
        }
        return FALSE;
    }

    public function removeChildItem($item, $data = null) {
        $repository = $this->getRepository();
        if (is_string($context)) {
            $name = $context;
            $context = array();
            $context['name'] = $name;
        }
        $context = $this->getReposipopulateAttributeListdContext($context);
        return $repository->getRow()->removeChild($context);
    }

    public function removeChild($item, $data = NULL) {
        return $this->removeChildItem($item, $data);
    }

    public static function find($item = NULL, $recursive = FALSE) {
        if ($recursive) {
            $entity = parent::find($item);
            return $entity;
        } else {
            $parent = self::getRoot();
            return $parent->getChild($item);
        }
    }

    public static function findAll($context, $recursive = FALSE) {

        if ($recursive) {
            return parent::findAll($context);
        }

        $parent = self::getRoot($context);

        return $parent->getChildren($context);
    }

    //tree delete all delete obj and all related child items
    public function removeChidren($context = null, $recursive = FALSE) {
        $children = $this->getChildren($context, $recursive);
        foreach ($children as $obj) {
            $this->removeChildItem($obj);
        }
        //parent::delete($context);
    }

    public static function delete($context) {
        if ($context instanceof BTreeEntity) {
            $obj = $context;
            $obj->removeChidren(NULL, TRUE);
            parent::delete($context->getId());
        }
    }

    public function getFullName($seperator = '.', $data = null) {

        if ($this->fullName != NULL)
            return $this->fullName;

        if ($this->getName() == 'root' && $this->parentId == 0)
            return 'root';

        $parents = $this->getParent(TRUE);

        if ($parents instanceof BTreeEntity) {
            if ($parents->getName() == 'root' && $parents->parentId == 0)
                return $this->getName();
        }

        $parents = array_reverse($parents);

        $names = array();

        foreach ($parents as $parent) {
            if ($parent->getName() != 'root') {// not root node
                array_push($names, $parent->getName());
            }
        }

        //add self name
        array_push($names, $this->getName());

        if ($seperator != NULL) {
            $rName = NULL;
            foreach ($names as $name) {
                if ($rName == NULL)
                    $rName = $name;
                else
                    $rName .= $seperator . $name;
            }
            return $rName;
        }

        return $names;
    }

    public function getRepository($data = NULL, $reload = FALSE) {
        $repository = parent::getRepository($data, $reload);
        $repository->addSearchablePropertyList('fullName');
        $repository->addSearchablePropertyList('name');
        $repository->addSearchablePropertyList('parentId');
        $repository->addSearchablePropertyList('spaceId');
        $repository->addSearchablePropertyList('appId');
        return $repository;
    }

    public function save($context = null) {
        $parentId = $this->parentId;
        if (is_array($context) && isset($context['parentId'])) {
            $parentId = $context['parentId'];
        }
        if ($context instanceof BTreeEntity) {
            $parentId = $context->parentId;
        }

        if ($parentId == NULL && $this->name != 'root') {
            //add item just under root
            $this->fullName = $this->name;
            $class = get_class($this);
            $this->parentId = $class::getRoot()->getId();
            //$this->save($context);
        }

        /*
          if ($this->parentId != NULL) {
          //always refine full name
          $parentFullName = $this->getParent()->getFullName();
          if($parentFullName == 'root')
          $this->fullName = $this->name;
          else {
          $this->fullName = $parentFullName . '.' . $this->name;
          }
          }
         * 
         */

        return parent::save($context);

        if ($this->getId() > 0 && $this->fullName == NULL) {
            $this->fullName = $this->getFullName();
            $this->save();
        }
    }

}

?>
